/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#include "物理/intern/S_Physics.h"


typedef struct {
	uint32 粒子索引;
	uint32 体素索引;
}S_粒子排序键值;

typedef enum {
	e_流体,
	e_刚体,
}E_PBF粒子类型;


struct S_PhysicspPBF : public S_Physics {
	//坐标 质量
	S_GPU内存块 m_坐标;
	S_GPU内存块 m_前一帧坐标;

	//速度 生命
	S_GPU内存块 m_速度和年龄;
	S_GPU内存块 m_加速度;
	S_GPU内存块 m_碰撞质量_密度_lambda;
	S_GPU内存块 m_质量;
	//步进 年龄
	S_GPU内存块 m_Delta;
	//粒子摩擦阻尼
	S_GPU内存块 m_摩擦阻尼;
	//（类型|状态） 链接区间索引(起始索引,链接数量) 寿命 
	S_GPU内存块 m_粒子类型状态;

	//uvec4 
	S_GPU内存块 m_粒子相互链接;
	//
	//S_GPU内存块 m_刚体;

	
	S_GPU内存块 m_排序键值;
	S_GPU内存块 m_排序临时键值;
	S_GPU内存块 m_排序键值偏移A;
	S_GPU内存块 m_排序键值偏移B;
	S_GPU内存块 m_排序键值区间数量;
	S_GPU内存块 m_排序跳过交换;

	S_GPU内存块 m_单元粒子索引网格;
	S_GPU内存块 m_飞溅粒子排序键值;
	//S_GPU内存块索引 m_单元粒子数量网格;

	S_GPU内存块 m_飞溅坐标;
	S_GPU内存块 m_飞溅速度;
	S_GPU内存块 m_飞溅寿命;
	
	S_GPU内存块 m_飞溅粒子发射排序键值A;
	S_GPU内存块 m_飞溅粒子发射排序键值B;
	S_GPU内存块 m_飞溅粒子排序区间数量;
	S_GPU内存块 m_发射飞溅粒子排序键值偏移A;
	S_GPU内存块 m_发射飞溅粒子排序键值偏移B;
	uint32			m_已有飞溅粒子数量;
	uint32			m_已有发射粒子索引数量A;
	uint32			m_已有发射粒子索引数量B;
	uint32			m_有效飞溅粒子数量;
	//uint32			m_飞溅粒子索引缓存已有数量;

	S_GPU内存块 m_力;



	S_GPU内存块 m_解算参数;


	vec3	m_域偏移;
	uvec3	m_网格分辨率;
	float32	m_网格单元大小;
	//不是所有粒子
	uint32	m_粒子数量;
	int32 m_MumIterations;
	int32 m_NumSubsteps;


	S_GPU计算* m_GPU计算_粒子施加力;

	S_GPU计算* m_GPU计算_粒子排序;
	S_GPU计算* m_GPU计算_粒子排序偏移;
	S_GPU计算* m_GPU计算_粒子排序偏移复制;
	S_GPU计算* m_GPU计算_粒子排序合并;
	S_GPU计算* m_GPU计算_粒子排序合并复制;

	S_GPU计算* m_GPU计算_清除粒子在网格索引;
	S_GPU计算* m_GPU计算_粒子在网格索引;
	
	S_GPU计算* m_GPU计算_计算密度和压力;
	S_GPU计算* m_GPU计算_粒子力计算;
	S_GPU计算* m_GPU计算_粒子碰撞更新;
	//S_GPU计算* m_GPU计算_粒子粘力;
	S_GPU计算* m_GPU计算_粒子粘力;


	S_GPU计算* m_GPU计算_飞溅粒子生成排序键值;
	S_GPU计算* m_GPU计算_飞溅粒子排序偏移;
	S_GPU计算* m_GPU计算_飞溅粒子排序偏移复制;
	S_GPU计算* m_GPU计算_飞溅粒子排序合并;
	S_GPU计算* m_GPU计算_计算飞溅粒子生成;
	S_GPU计算* m_GPU计算_计算飞溅粒子运动;
	//S_GPU计算* m_GPU计算_计算飞溅粒子更新;

	S_GPU计算* m_GPU计算_飞溅粒子发射排序;
	S_GPU计算* m_GPU计算_飞溅粒子发射排序偏移;
	S_GPU计算* m_GPU计算_飞溅粒子发射排序偏移复制;
	S_GPU计算* m_GPU计算_飞溅粒子发射排序合并;
	S_GPU计算* m_GPU计算_飞溅粒子发射时间合并;



	S_GPU计算* m_GPU计算_粒子可视;
	S_GPU计算* m_GPU计算_域可视;


	S_渲染层* m_计数层;


	//S_PBF_Params	m_解算参数;
	bool	m_开启飞溅粒子;


	S_GPU参数槽	m_碰撞参数;


	std::map<std::u16string, S_物理体*>	m_物理体;
	std::vector<S_Object*>				m_碰撞物体;
	uint32 m_粒子添加偏移;


	S_PhysicspPBF(S_设备环境& ctx, std::wstring name = L"PBF");
	~S_PhysicspPBF();


	void	f_Update();
	void	f_划分粒子();
	void	f_排序粒子();
	void	f_计算力(float32 dt);
	void	f_生成飞溅粒子(float32 dt);
	void	f_发射飞溅粒子();
	void	f_更新粒子();

};



S_PhysicspPBF*	f_pbf_创建PBF(S_设备环境& ctx);
void			f_pbf_销毁PBF(S_PhysicspPBF* phy);



void f_pbf_重构(S_PhysicspPBF& pbf);

void f_pbf_设置网格维度(S_PhysicspPBF& pbf, const vec3& 网格大小, const vec3& 域偏移, float32 单元大小);

void f_pbf_添加物理体(S_PhysicspPBF& pbf, S_PhyBodyArray* body);

void f_pbf_设置飞溅粒子(S_PhysicspPBF& pbf, S_PhyBodyArray* body);

void f_pbf_重置(S_PhysicspPBF& pbf);

void f_pbf_解算(S_PhysicspPBF& pbf, float32 时间步进);

void f_pbf_取调试粒子(S_PhysicspPBF& pbf, S_物体* ob, uint8 调试信息类型);

void f_pbf_初始化解算参数(S_PBF_Params& p);

void f_pbf_分配飞溅粒子(S_PhysicspPBF& pbf, bool 是否开启, uint32 分配数量);

void f_pbf_添加力(S_PhysicspPBF& pbf, const std::vector<S_PBF_force>& 力);

void f_pbf_set模拟参数(S_PhysicspPBF& pbf, const S_PBF_Params& 模拟参数);

void f_pbf_发射粒子(S_PhysicspPBF& pbf, S_物理体* body, const S_Vec3Array* point, const S_Vec3Array* vel);

void f_pbf_更新粒子渲染(S_PhysicspPBF& pbf, float32 子帧步进);

bool f_pbf_读取缓存(S_PhysicspPBF& pbf, const std::string& path, E_物理缓存方式 缓存方式, bool 前一帧);

void f_pbf_写入缓存(S_PhysicspPBF& pbf, const std::string& path, E_物理缓存方式 缓存方式);

void f_pbf_清除模拟帧标记(S_PhysicspPBF& pbf, int32 s, int32 e);

bool f_pbf_内部重构(S_PhysicspPBF& pbf);



